#include "hw_tracing.h"
#include "stdio.h"
#include "string.h"

#define delay_us(__us)  delay_cycles((CPUCLK_FREQ/1000000)*__us)
#define delay_ms(__ms)  delay_cycles((CPUCLK_FREQ/1000)*__ms)
#define I2C_DELAY_TIME 10   //I2C的基本时序时间


static void i2c_start(void)
{
        TRACING_SDA_OUT();

        TRACING_SCL(0);
        TRACING_SDA(1);
        TRACING_SCL(1);

        delay_us(I2C_DELAY_TIME);

        TRACING_SDA(0);
        delay_us(I2C_DELAY_TIME);
        TRACING_SCL(0);
        delay_us(I2C_DELAY_TIME);
}

static void i2c_stop(void)
{
        TRACING_SDA_OUT();
        TRACING_SCL(0);
        TRACING_SDA(0);

        TRACING_SCL(1);
        delay_us(I2C_DELAY_TIME);
        TRACING_SDA(1);
        delay_us(I2C_DELAY_TIME);

}

/******************************************************************
 * 函 数 说 明：主机发送应答或者非应答信号
 * 函 数 形 参：0发送应答  1发送非应答
******************************************************************/
static void i2c_send_ack(unsigned char ack)
{
        TRACING_SDA_OUT();
        TRACING_SCL(0);
        TRACING_SDA(0);
        delay_us(I2C_DELAY_TIME);
        if(!ack) TRACING_SDA(0);
        else     TRACING_SDA(1);
        TRACING_SCL(1);
        delay_us(I2C_DELAY_TIME);
        TRACING_SCL(0);
        TRACING_SDA(1);
}


/******************************************************************
 * 函 数 说 明：等待从机应答
 * 函 数 返 回：0有应答  1超时无应答
******************************************************************/
static unsigned char i2c_wait_ack(void)
{
        char ack = 0;
        char ack_flag = 50;
        TRACING_SDA_IN();
        TRACING_SDA(1);
        while( (TRACING_SDA_GET()==1) && ( ack_flag ) )
        {
                ack_flag--;
                delay_us(I2C_DELAY_TIME);
        }

        if( ack_flag == 0 )
        {
                i2c_stop();
                return 1;
        }
        else
        {
                TRACING_SCL(1);
                delay_us(I2C_DELAY_TIME);
                TRACING_SCL(0);
                TRACING_SDA_OUT();
        }
        return ack;
}

/******************************************************************
 * 函 数 说 明：写入一个字节
 * 函 数 形 参：dat要写人的数据
******************************************************************/
static void i2c_send_byte(uint8_t dat)
{
        int i = 0;
        TRACING_SDA_OUT();
        TRACING_SCL(0);//拉低时钟开始数据传输

        for( i = 0; i < 8; i++ )
        {
                TRACING_SDA( (dat & 0x80) >> 7 );
                delay_us(2);
                TRACING_SCL(1);
                delay_us(I2C_DELAY_TIME);
                TRACING_SCL(0);
                delay_us(I2C_DELAY_TIME);
                dat<<=1;
        }
}

/******************************************************************
 * 函 数 说 明：IIC读时序
 * 函 数 返 回：读到的数据
******************************************************************/
static unsigned char i2c_read_byte(void)
{
    unsigned char i,receive=0;
    TRACING_SDA_IN();//TRACING_SDA设置为输入
    for(i=0;i<8;i++ )
    {
        TRACING_SCL(0);
        delay_us(I2C_DELAY_TIME);
        TRACING_SCL(1);
        delay_us(I2C_DELAY_TIME);
        receive<<=1;
        if( TRACING_SDA_GET() )
        {
            receive|=1;
        }
        delay_us(I2C_DELAY_TIME);
    }

    TRACING_SCL(0);

    return receive;
}

/**
 * i2c地址扫描
 * @param scan_addr 扫描出来的地址存放,数值不为0的为扫描到的地址，扫到的地址会挨个放在数组的最前面
 * @return 返回扫描到的设备数量, 0为无设备发现
 */
uint8_t i2c_scan(void)
{
        for(int i = 1; i < 127; i++)
        {
                i2c_start();//发送开始信号
                i2c_send_byte((i<<1)|1);//发送地址写
                if( i2c_wait_ack() == 1 )//如果从机不应答
                {
                        i2c_stop(); 
                }
                else
                {
                        return i;
                }
                i2c_stop(); 
                delay_ms(50);
                 
        }
        return 0;

}


char tracing_data_O;//十进制
char tracing_data_B[8];//二进制数组

//获取循迹模块8路传感器的数据 保存为8位二进制数据
//dev_addr=I2C设备的地址
//使用传感器内置芯片直接读取01电平
int get_tracing_data(uint8_t dev_addr)
{
    i2c_start();//发送开始信号
    i2c_send_byte(dev_addr + 0);//发送地址+写命令
    if( i2c_wait_ack() == 1 ) { i2c_stop(); return 1; }//等待从机应答

    i2c_send_byte(0XDD);//发送连续读取的命令
    if( i2c_wait_ack() == 1 ) { i2c_stop(); return 2;}//等待从机应答

    i2c_stop();//发送停止信号

    i2c_start();//发送开始信号
    i2c_send_byte(dev_addr + 1);//发送地址+读命令
 
    if( i2c_wait_ack() == 1 ) { i2c_stop(); return 3;}//等待从机应答
    
    tracing_data_O = i2c_read_byte();//读取数据
    i2c_send_ack(1);//主机发送非应答信

    i2c_stop();//发送停止信号

    return 0;
}

//十进制数按位成二进制数取出
void O_TO_B(void) 
{
        for(int i = 0; i<8;i++)
        {
            tracing_data_B[i] = (tracing_data_O >> i) & 1;
        }

}
volatile uint8_t H0, H1, H2, H3, H4, H5, H6, H7;
/**
 * 获得误差数据作为PID的输入，避免进行浮点数乘法
 * @param 无
 * @return 返回扫描到的设备数量, 0为无设备发现
 */
int tracing_Digital(void)
{
        get_tracing_data(TRACING_ADDRESS);
        O_TO_B();

        if (!tracing_data_B[7]) return 9;
        if (!tracing_data_B[0]) return -9;

        if (!tracing_data_B[6]) return 7;
        if (!tracing_data_B[1]) return -7;

        if (!tracing_data_B[5]) return 5;
        if (!tracing_data_B[2]) return -5;

        if (!tracing_data_B[4] && !tracing_data_B[3]) return 0;
        if (!tracing_data_B[4]) return 3;
        if (!tracing_data_B[3]) return -3;

        return 0;
}

//ping网络诊断
int pingtracing(uint8_t dev_addr)
{
    int pingdata;
    i2c_start();//发送开始信号
    i2c_send_byte(dev_addr + 0);//发送地址+写命令
    if( i2c_wait_ack() == 1 ) { i2c_stop(); return 1; }//等待从机应答

    i2c_send_byte(0xAA);//发送连续读取的命令
    if( i2c_wait_ack() == 1 ) { i2c_stop(); return 2;}//等待从机应答
    i2c_start();//发送开始信号
    i2c_send_byte(dev_addr + 1);//发送地址+读命令
 
    if( i2c_wait_ack() == 1 ) { i2c_stop(); return 3;}//等待从机应答

    pingdata = i2c_read_byte();//读取数据
    i2c_send_ack(1);//主机发送非应答信

    i2c_stop();//发送停止信号
    return pingdata;
}
